/*
REWRITTEN BY XINEF
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "black_temple.h"
#include "Spell.h"

enum Says
{
	//Suffering
	SUFF_SAY_FREED						= 0,
	SUFF_SAY_AGGRO						= 1,
	SUFF_SAY_SLAY						= 2,
	SUFF_SAY_RECAP						= 3,
	SUFF_SAY_AFTER						= 4,
	SUFF_SAY_ENRAGE						= 5,
	SUFF_EMOTE_ENRAGE					= 6,

	//Desire
	DESI_SAY_FREED						= 0,
	DESI_SAY_SLAY						= 1,
	DESI_SAY_SPEC						= 2,
	DESI_SAY_RECAP						= 3,
	DESI_SAY_AFTER						= 4,

	//Anger
	ANGER_SAY_FREED						= 0,
	ANGER_SAY_SLAY						= 1,
	ANGER_SAY_SPEC						= 2,
	ANGER_SAY_RECAP						= 3,
	ANGER_SAY_DEATH						= 4
};

enum Spells
{
	SPELL_EMERGE_VISUAL					= 50142,
	SPELL_SUMMON_ESSENCE_OF_SUFFERING	= 41488,
	SPELL_SUMMON_ESSENCE_OF_DESIRE		= 41493,
	SPELL_SUMMON_ESSENCE_OF_ANGER		= 41496,
	SPELL_SUMMON_ENSLAVED_SOUL			= 41537,

	// Suffering
	SPELL_AURA_OF_SUFFERING				= 41292,
	SPELL_AURA_OF_SUFFERING_TRIGGER		= 42017,
	SPELL_ESSENCE_OF_SUFFERING_PASSIVE	= 41296,
	SPELL_ESSENCE_OF_SUFFERING_PASSIVE2	= 41623,
	SPELL_FRENZY						= 41305,
	SPELL_SOUL_DRAIN					= 41303,

	// Desire
	SPELL_AURA_OF_DESIRE				= 41350,
	SPELL_AURA_OF_DESIRE_DAMAGE			= 41352,
	SPELL_RUNE_SHIELD					= 41431,
	SPELL_DEADEN						= 41410,
	SPELL_SPIRIT_SHOCK					= 41426,

	// Anger
	SPELL_AURA_OF_ANGER					= 41337,
	SPELL_SPITE							= 41376,
	SPELL_SPITE_DAMAGE					= 41377,
	SPELL_SOUL_SCREAM					= 41545,
	SPELL_SEETHE						= 41364
};

enum Misc
{
	ACTION_ESSENCE_OF_SUFFERING		= 1,
	ACTION_ESSENCE_OF_DESIRE		= 2,
	ACTION_ESSENCE_OF_ANGER			= 3,
	ACTION_ENGAGE_ESSENCE			= 4,

	EVENT_ESSENCE_OF_SUFFERING		= 1,
	EVENT_ESSENCE_OF_DESIRE			= 2,
	EVENT_ESSENCE_OF_ANGER			= 3,
	EVENT_ENGAGE_ESSENCE			= 4,
	EVENT_SPAWN_ENSLAVED_SOULS		= 5,
	EVENT_SPAWN_SOUL				= 6,
	EVENT_SUCK_ESSENCE				= 7,

	EVENT_SUFF_FRENZY				= 10,
	EVENT_SUFF_FRENZY_EMOTE			= 11,
	EVENT_SUFF_SOUL_DRAIN			= 12,

	EVENT_DESI_DEADEN				= 20,
	EVENT_DESI_SPIRIT_SHOCK			= 21,
	EVENT_DESI_RUNE_SHIELD			= 22,

	EVENT_ANGER_SPITE				= 30,
	EVENT_ANGER_SOUL_SCREAM			= 31,
	EVENT_ANGER_SEETHE				= 32,

	EVENT_KILL_TALK					= 100,
	POINT_GO_BACK					= 1
};

class SuckBackEvent : public BasicEvent
{
	public:
		SuckBackEvent(Creature& owner, uint32 action) : BasicEvent(), _owner(owner), _action(action) { }

		bool Execute(uint64 /*eventTime*/, uint32 /*diff*/)
		{
			if (_owner.IsSummon())
				if (Unit* summoner = _owner.ToTempSummon()->GetSummoner())
				{
					summoner->GetAI()->DoAction(_action);
					_owner.SetStandState(UNIT_STAND_STATE_SUBMERGED);
					_owner.DespawnOrUnsummon(200);
				}
			return true;
		}

	private:
		Creature& _owner;
		uint32 _action;
};

class boss_reliquary_of_souls : public CreatureScript
{
	public:
		boss_reliquary_of_souls() : CreatureScript("boss_reliquary_of_souls") { }

		CreatureAI* GetAI(Creature* creature) const
		{
			return GetInstanceAI<boss_reliquary_of_soulsAI>(creature);
		}

		struct boss_reliquary_of_soulsAI : public BossAI
		{
			boss_reliquary_of_soulsAI(Creature* creature) : BossAI(creature, DATA_RELIQUARY_OF_SOULS)
			{
			}

			void Reset()
			{
				BossAI::Reset();
				me->SetStandState(UNIT_STAND_STATE_SLEEP);
			}

			void MoveInLineOfSight(Unit* who)
			{
				if (!who || me->getStandState() != UNIT_STAND_STATE_SLEEP || who->GetTypeId() != TYPEID_PLAYER || me->GetDistance2d(who) > 90.0f || who->ToPlayer()->IsGameMaster())
					return;

				me->SetInCombatWithZone();
				events.ScheduleEvent(EVENT_ESSENCE_OF_SUFFERING, 5000); // ZOMG! 15000);
				me->SetStandState(UNIT_STAND_STATE_STAND);
			}

			void DoAction(int32 param)
			{
				if (param == ACTION_ESSENCE_OF_SUFFERING)
				{
					me->SetStandState(UNIT_STAND_STATE_STAND);
					events.ScheduleEvent(EVENT_SUCK_ESSENCE, 1000);
					events.ScheduleEvent(EVENT_SPAWN_ENSLAVED_SOULS, 8000);
					events.ScheduleEvent(EVENT_ESSENCE_OF_DESIRE, 38000);
				}
				else if (param == ACTION_ESSENCE_OF_DESIRE)
				{
					me->SetStandState(UNIT_STAND_STATE_STAND);
					events.ScheduleEvent(EVENT_SUCK_ESSENCE, 1000);
					events.ScheduleEvent(EVENT_SPAWN_ENSLAVED_SOULS, 8000);
					events.ScheduleEvent(EVENT_ESSENCE_OF_ANGER, 38000);
				}
				else if (param == ACTION_ESSENCE_OF_ANGER)
				{
				}
			}

			void EnterCombat(Unit* who)
			{
				BossAI::EnterCombat(who);
			}

			void JustSummoned(Creature* summon)
			{
				summons.Summon(summon);
				if (summon->GetEntry() == NPC_ENSLAVED_SOUL)
					return;

				summon->SetReactState(REACT_PASSIVE);
				summon->CastSpell(summon, SPELL_EMERGE_VISUAL, true);
				events.ScheduleEvent(EVENT_ENGAGE_ESSENCE, 4000);
			}

			void SummonedCreatureDies(Creature* summon, Unit*)
			{
				summons.Despawn(summon);
			}

			void AttackStart(Unit*) { }


			void JustDied(Unit* killer)
			{
				summons.clear();
				BossAI::JustDied(killer);
			}

			void UpdateAI(uint32 diff)
			{
				if (me->getStandState() == UNIT_STAND_STATE_SLEEP)
					return;

				events.Update(diff);
				switch (events.ExecuteEvent())
				{
					case EVENT_SUCK_ESSENCE:
						me->SetStandState(UNIT_STAND_STATE_STAND);
						break;
					case EVENT_ENGAGE_ESSENCE:
						summons.DoAction(ACTION_ENGAGE_ESSENCE);
						break;
					case EVENT_ESSENCE_OF_SUFFERING:
						me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
						me->CastSpell(me, SPELL_SUMMON_ESSENCE_OF_SUFFERING, false);
						break;
					case EVENT_ESSENCE_OF_DESIRE:
						summons.DespawnAll();
						me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
						me->CastSpell(me, SPELL_SUMMON_ESSENCE_OF_DESIRE, false);
						break;
					case EVENT_ESSENCE_OF_ANGER:
						summons.DespawnAll();
						me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
						me->CastSpell(me, SPELL_SUMMON_ESSENCE_OF_ANGER, false);
						break;
					case EVENT_SPAWN_ENSLAVED_SOULS:
						events.ScheduleEvent(EVENT_SPAWN_SOUL, 0);
						events.ScheduleEvent(EVENT_SPAWN_SOUL, 0);
						for (uint8 i = 0; i < 16; ++i)
							events.ScheduleEvent(EVENT_SPAWN_SOUL, i*1200);
						break;
					case EVENT_SPAWN_SOUL:
						me->CastCustomSpell(SPELL_SUMMON_ENSLAVED_SOUL, SPELLVALUE_MAX_TARGETS, 1, me, false);
						break;
				}

				EnterEvadeIfOutOfCombatArea();
			}
	
			bool CheckEvadeIfOutOfCombatArea() const
			{
				return !SelectTargetFromPlayerList(80.0f);
			}
		};
};

class boss_essence_of_suffering : public CreatureScript
{
	public:
		boss_essence_of_suffering() : CreatureScript("boss_essence_of_suffering") { }

		CreatureAI* GetAI(Creature* creature) const
		{
			return new boss_essence_of_sufferingAI(creature);
		}

		struct boss_essence_of_sufferingAI : public ScriptedAI
		{
			boss_essence_of_sufferingAI(Creature* creature) : ScriptedAI(creature) { }

			EventMap events;

			void Reset()
			{
				events.Reset();
			}

			void DoAction(int32 param)
			{
				if (param == ACTION_ENGAGE_ESSENCE)
				{
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NON_ATTACKABLE);
					me->SetReactState(REACT_AGGRESSIVE);
					me->SetInCombatWithZone();
				}
			}

			void MovementInform(uint32 type, uint32 id)
			{
				if (type != POINT_MOTION_TYPE || id != POINT_GO_BACK)
					return;

				me->m_Events.AddEvent(new SuckBackEvent(*me, ACTION_ESSENCE_OF_SUFFERING), me->m_Events.CalculateTime(1500));
				me->SetTarget(0);
				me->SetFacingTo(M_PI/2.0f);
			}

			void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask)
			{
				if (damage >= me->GetHealth())
				{
					damage = 0;
					if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
					{
						me->RemoveAurasDueToSpell(SPELL_ESSENCE_OF_SUFFERING_PASSIVE); // prevent fixate from triggering
						me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
						Talk(SUFF_SAY_RECAP);
						me->SetReactState(REACT_PASSIVE);
						me->GetMotionMaster()->Clear();
						me->GetMotionMaster()->MovePoint(POINT_GO_BACK, me->GetHomePosition(), false);
						events.Reset();
					}
				}
			}

			void KilledUnit(Unit* /*victim*/)
			{
				if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
				{
					Talk(SUFF_SAY_SLAY);
					events.ScheduleEvent(EVENT_KILL_TALK, 6000);
				}
			}

			void EnterCombat(Unit* /*who*/)
			{
				Talk(SUFF_SAY_FREED);
				me->CastSpell(me, SPELL_AURA_OF_SUFFERING, true);
				me->CastSpell(me, SPELL_ESSENCE_OF_SUFFERING_PASSIVE, true);
				me->CastSpell(me, SPELL_ESSENCE_OF_SUFFERING_PASSIVE2, true);

				events.ScheduleEvent(EVENT_SUFF_FRENZY, 45000);
				events.ScheduleEvent(EVENT_SUFF_SOUL_DRAIN, 25000);
			}

			void UpdateAI(uint32 diff)
			{
				if (!UpdateVictim())
					return;

				events.Update(diff);
				if (me->HasUnitState(UNIT_STATE_CASTING))
					return;

				switch (events.ExecuteEvent())
				{
					case EVENT_SUFF_SOUL_DRAIN:
						me->CastCustomSpell(SPELL_SOUL_DRAIN, SPELLVALUE_MAX_TARGETS, 3, me, false);
						events.ScheduleEvent(EVENT_SUFF_SOUL_DRAIN, 30000);
						break;
					case EVENT_SUFF_FRENZY:
						Talk(SUFF_SAY_ENRAGE);
						Talk(SUFF_EMOTE_ENRAGE);
						me->CastSpell(me, SPELL_FRENZY, false);
						events.ScheduleEvent(EVENT_SUFF_FRENZY, 45000);
						events.ScheduleEvent(EVENT_SUFF_FRENZY_EMOTE, 3000);
						break;
					case EVENT_SUFF_FRENZY_EMOTE:
						Talk(SUFF_EMOTE_ENRAGE);
						break;
				}

				DoMeleeAttackIfReady();
			}
		};
};

class boss_essence_of_desire : public CreatureScript
{
	public:
		boss_essence_of_desire() : CreatureScript("boss_essence_of_desire") { }

		CreatureAI* GetAI(Creature* creature) const
		{
			return new boss_essence_of_desireAI(creature);
		}

		struct boss_essence_of_desireAI : public ScriptedAI
		{
			boss_essence_of_desireAI(Creature* creature) : ScriptedAI(creature) { }

			EventMap events;

			void Reset()
			{
				events.Reset();
			}

			void DoAction(int32 param)
			{
				if (param == ACTION_ENGAGE_ESSENCE)
				{
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NON_ATTACKABLE);
					me->SetReactState(REACT_AGGRESSIVE);
					me->SetInCombatWithZone();
				}
			}

			void MovementInform(uint32 type, uint32 id)
			{
				if (type != POINT_MOTION_TYPE || id != POINT_GO_BACK)
					return;

				me->m_Events.AddEvent(new SuckBackEvent(*me, ACTION_ESSENCE_OF_DESIRE), me->m_Events.CalculateTime(1500));
				me->SetTarget(0);
				me->SetFacingTo(M_PI/2.0f);
			}

			void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask)
			{
				if (damage >= me->GetHealth())
				{
					damage = 0;
					if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
					{
						me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
						Talk(DESI_SAY_RECAP);
						me->SetReactState(REACT_PASSIVE);
						me->GetMotionMaster()->Clear();
						me->GetMotionMaster()->MovePoint(POINT_GO_BACK, me->GetHomePosition(), false);
						events.Reset();
					}
				}
			}

			void KilledUnit(Unit* /*victim*/)
			{
				if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
				{
					Talk(DESI_SAY_SLAY);
					events.ScheduleEvent(EVENT_KILL_TALK, 6000);
				}
			}

			void EnterCombat(Unit* /*who*/)
			{
				Talk(DESI_SAY_FREED);
				me->CastSpell(me, SPELL_AURA_OF_DESIRE, true);
					
				events.ScheduleEvent(EVENT_DESI_DEADEN, 28000);
				events.ScheduleEvent(EVENT_DESI_SPIRIT_SHOCK, 20000);
				events.ScheduleEvent(EVENT_DESI_RUNE_SHIELD, 13000);
			}

			void UpdateAI(uint32 diff)
			{
				if (!UpdateVictim())
					return;

				events.Update(diff);
				if (me->HasUnitState(UNIT_STATE_CASTING))
					return;

				switch (events.ExecuteEvent())
				{
					case EVENT_DESI_DEADEN:
						if (roll_chance_i(50))
							Talk(DESI_SAY_SPEC);
						me->CastSpell(me->GetVictim(), SPELL_DEADEN, false);
						events.ScheduleEvent(EVENT_DESI_DEADEN, 31000);
						break;
					case EVENT_DESI_SPIRIT_SHOCK:
						me->CastSpell(me->GetVictim(), SPELL_SPIRIT_SHOCK, false);
						events.ScheduleEvent(EVENT_DESI_SPIRIT_SHOCK, 12000);
						break;
					case EVENT_DESI_RUNE_SHIELD:
						me->CastSpell(me, SPELL_RUNE_SHIELD, false);
						events.ScheduleEvent(EVENT_DESI_RUNE_SHIELD, 15000);
						break;
				}

				DoMeleeAttackIfReady();
			}
		};
};

class boss_essence_of_anger : public CreatureScript
{
	public:
		boss_essence_of_anger() : CreatureScript("boss_essence_of_anger") { }

		CreatureAI* GetAI(Creature* creature) const
		{
			return new boss_essence_of_angerAI(creature);
		}

		struct boss_essence_of_angerAI : public ScriptedAI
		{
			boss_essence_of_angerAI(Creature* creature) : ScriptedAI(creature) { }

			EventMap events;
			uint64 targetGUID;

			void Reset()
			{
				targetGUID = 0;
				events.Reset();
			}

			void DoAction(int32 param)
			{
				if (param == ACTION_ENGAGE_ESSENCE)
				{
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NON_ATTACKABLE);
					me->SetReactState(REACT_AGGRESSIVE);
					me->SetInCombatWithZone();
				}
			}

			void KilledUnit(Unit* /*victim*/)
			{
				if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
				{
					Talk(ANGER_SAY_SLAY);
					events.ScheduleEvent(EVENT_KILL_TALK, 6000);
				}
			}

			void JustDied(Unit* killer)
			{
				Talk(ANGER_SAY_DEATH);
				if (me->IsSummon())
					if (Unit* summoner = me->ToTempSummon()->GetSummoner())
						Unit::Kill(summoner, summoner);
			}

			void EnterCombat(Unit* /*who*/)
			{
				Talk(ANGER_SAY_FREED);
				me->CastSpell(me, SPELL_AURA_OF_ANGER, true);
					
				events.ScheduleEvent(EVENT_ANGER_SPITE, 15000);
				events.ScheduleEvent(EVENT_ANGER_SOUL_SCREAM, 10000);
				events.ScheduleEvent(EVENT_ANGER_SEETHE, 1000);
			}

			void UpdateAI(uint32 diff)
			{
				if (!UpdateVictim())
					return;

				events.Update(diff);
				if (me->HasUnitState(UNIT_STATE_CASTING))
					return;

				switch (events.ExecuteEvent())
				{
					case EVENT_ANGER_SPITE:
						if (roll_chance_i(30))
							Talk(ANGER_SAY_SPEC);
						me->CastCustomSpell(SPELL_SPITE, SPELLVALUE_MAX_TARGETS, 3, me, false);
						events.ScheduleEvent(EVENT_ANGER_SPITE, 25000);
						break;
					case EVENT_ANGER_SOUL_SCREAM:
						me->CastSpell(me->GetVictim(), SPELL_SOUL_SCREAM, false);
						events.ScheduleEvent(EVENT_ANGER_SOUL_SCREAM, 10000);
						break;
					case EVENT_ANGER_SEETHE:
						if (targetGUID && targetGUID != me->GetVictim()->GetGUID())
							me->CastSpell(me, SPELL_SEETHE, false);
						// victim can be lost
						if (me->GetVictim())
							targetGUID = me->GetVictim()->GetGUID();
						events.ScheduleEvent(EVENT_ANGER_SEETHE, 1000);
						break;

				}

				DoMeleeAttackIfReady();
			}
		};
};

class spell_reliquary_of_souls_aura_of_suffering : public SpellScriptLoader
{
	public:
		spell_reliquary_of_souls_aura_of_suffering() : SpellScriptLoader("spell_reliquary_of_souls_aura_of_suffering") { }

		class spell_reliquary_of_souls_aura_of_suffering_AuraScript : public AuraScript
		{
			PrepareAuraScript(spell_reliquary_of_souls_aura_of_suffering_AuraScript)

			void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
			{
				GetTarget()->CastSpell(GetTarget(), SPELL_AURA_OF_SUFFERING_TRIGGER, true);
			}

			void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
			{
				GetTarget()->RemoveAurasDueToSpell(SPELL_AURA_OF_SUFFERING_TRIGGER);
			}

			void Register()
			{
				OnEffectApply += AuraEffectApplyFn(spell_reliquary_of_souls_aura_of_suffering_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT, AURA_EFFECT_HANDLE_REAL);
				OnEffectRemove += AuraEffectRemoveFn(spell_reliquary_of_souls_aura_of_suffering_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT, AURA_EFFECT_HANDLE_REAL);
			}
		};

		AuraScript* GetAuraScript() const
		{
			return new spell_reliquary_of_souls_aura_of_suffering_AuraScript();
		}
};

class spell_reliquary_of_souls_fixate : public SpellScriptLoader
{
    public:
        spell_reliquary_of_souls_fixate() : SpellScriptLoader("spell_reliquary_of_souls_fixate") { }

        class spell_reliquary_of_souls_fixate_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_reliquary_of_souls_fixate_SpellScript);

            void FilterTargets(std::list<WorldObject*>& targets)
            {
				if (targets.empty())
					return;

				targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster()));
				WorldObject* target = targets.front();
				targets.clear();
				targets.push_back(target);
            }

            void Register()
            {
                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_reliquary_of_souls_fixate_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_reliquary_of_souls_fixate_SpellScript();
        }

		class spell_reliquary_of_souls_fixate_AuraScript : public AuraScript
		{
			PrepareAuraScript(spell_reliquary_of_souls_fixate_AuraScript)

			void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
			{
				if (Unit* caster = GetCaster())
					caster->RemoveAurasDueToSpell(GetSpellInfo()->Effects[EFFECT_1].TriggerSpell, GetTarget()->GetGUID());
			}

			void Register()
			{
				OnEffectRemove += AuraEffectRemoveFn(spell_reliquary_of_souls_fixate_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
			}
		};

		AuraScript* GetAuraScript() const
		{
			return new spell_reliquary_of_souls_fixate_AuraScript();
		}
};

class spell_reliquary_of_souls_aura_of_desire : public SpellScriptLoader
{
    public:
        spell_reliquary_of_souls_aura_of_desire() : SpellScriptLoader("spell_reliquary_of_souls_aura_of_desire") { }

        class spell_reliquary_of_souls_aura_of_desire_AuraScript : public AuraScript
        {
            PrepareAuraScript(spell_reliquary_of_souls_aura_of_desire_AuraScript);

            bool CheckProc(ProcEventInfo& eventInfo)
            {
				return eventInfo.GetActor() && eventInfo.GetActionTarget();
            }

            void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
            {
                PreventDefaultAction();
				eventInfo.GetActionTarget()->CastCustomSpell(SPELL_AURA_OF_DESIRE_DAMAGE, SPELLVALUE_BASE_POINT0, eventInfo.GetDamageInfo()->GetDamage()/2, eventInfo.GetActor(), true);
            }

			void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
			{
				if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_2))
					amount = std::max<int32>(-100, -5*int32(effect->GetTickNumber()));
			}

			void Update(AuraEffect const* effect)
			{                
				PreventDefaultAction();
				if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1))
					effect->RecalculateAmount();
			}

            void Register()
            {
                DoCheckProc += AuraCheckProcFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::CheckProc);
                OnEffectProc += AuraEffectProcFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT);
				DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT);
				OnEffectPeriodic += AuraEffectPeriodicFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::Update, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
            }
        };

        AuraScript* GetAuraScript() const
        {
            return new spell_reliquary_of_souls_aura_of_desire_AuraScript();
        }
};

class spell_reliquary_of_souls_aura_of_anger : public SpellScriptLoader
{
    public:
        spell_reliquary_of_souls_aura_of_anger() : SpellScriptLoader("spell_reliquary_of_souls_aura_of_anger") { }

        class spell_reliquary_of_souls_aura_of_anger_AuraScript : public AuraScript
        {
            PrepareAuraScript(spell_reliquary_of_souls_aura_of_anger_AuraScript);

			void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
			{
				if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_0))
					amount = amount*effect->GetTickNumber();
			}

			void Update(AuraEffect const* effect)
			{
				if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_0))
					effect->RecalculateAmount();
				if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1))
					effect->RecalculateAmount();
			}

            void Register()
            {
				DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_reliquary_of_souls_aura_of_anger_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
				DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_reliquary_of_souls_aura_of_anger_AuraScript::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
				OnEffectPeriodic += AuraEffectPeriodicFn(spell_reliquary_of_souls_aura_of_anger_AuraScript::Update, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
            }
        };

        AuraScript* GetAuraScript() const
        {
            return new spell_reliquary_of_souls_aura_of_anger_AuraScript();
        }
};

class spell_reliquary_of_souls_spite : public SpellScriptLoader
{
    public:
        spell_reliquary_of_souls_spite() : SpellScriptLoader("spell_reliquary_of_souls_spite") { }

		class spell_reliquary_of_souls_spite_AuraScript : public AuraScript
		{
			PrepareAuraScript(spell_reliquary_of_souls_spite_AuraScript)

			void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
			{
				if (Unit* caster = GetCaster())
					caster->CastSpell(GetTarget(), SPELL_SPITE_DAMAGE, true);
			}

			void Register()
			{
				AfterEffectRemove += AuraEffectRemoveFn(spell_reliquary_of_souls_spite_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DAMAGE_IMMUNITY, AURA_EFFECT_HANDLE_REAL);
			}
		};

		AuraScript* GetAuraScript() const
		{
			return new spell_reliquary_of_souls_spite_AuraScript();
		}
};

void AddSC_boss_reliquary_of_souls()
{
    new boss_reliquary_of_souls();
    new boss_essence_of_suffering();
    new boss_essence_of_desire();
    new boss_essence_of_anger();
	new spell_reliquary_of_souls_aura_of_suffering();
	new spell_reliquary_of_souls_fixate();
	new spell_reliquary_of_souls_aura_of_desire();
	new spell_reliquary_of_souls_aura_of_anger();
	new spell_reliquary_of_souls_spite();
}
